/*
 * TypingStructure.c
 * NtTrace Analyzer
 * @author Gregoire JACOB (gregoire.jacob@orange-ftgroup.com)
 * @date 02/09/2008
 * @version 1.0
 */

#include ".\Includes\Analyzer.h"

void printTypedObject(struct TYPED_OBJ * object, int number){
	int i;
	printf("\\* Object %s%d: ",typestr[object->Type],number);
	printf("%s",object->ObjectName);
	printf("\nNature: %s\n",naturestr[object->Nature]);
	printf("Status: %d\n",object->Status);
	if(object->Nature==VAR){
		printf("Address: 0x%08X\n",object->Address);
		printf("Size: %d\n",object->Size);
	}else{
		printf("Handle:\n");
		for(i=0;i<object->nbref;i++){
			printf("  | -%08X\n",object->Handles[i]);
		}
	}
	printf("/* End Object\n");
}

void printfTypedObject(FILE * f, struct TYPED_OBJ * object, int number){
	int i;
	fprintf(f,"\\* Object %s%d: ",typestr[object->Type],number);
	fprintf(f,"%s",object->ObjectName);
	fprintf(f,"\nNature: %s\n",naturestr[object->Nature]);
	fprintf(f,"Status: %d\n",object->Status);
	if(object->Nature==VAR){
		fprintf(f,"Address: 0x%08X\n",object->Address);
		fprintf(f,"Size: %d\n",object->Size);
	}else{
		fprintf(f,"Handle:\n");
		for(i=0;i<object->nbref;i++){
			fprintf(f,"  | -%08X\n",object->Handles[i]);
		}
	}
	fprintf(f,"/* End Object\n");
}


void printTyping(struct TYPING * types){
	int i;

	printf("\\** Typing: *********************************************/\n");
	printf("Typed Object List:\n");
	for(i=0;i<types->nbobj;i++){
		printf("------------------------\n");
		printTypedObject(&types->objects[i],i);
	}
	printf("------------------------\n");
	printf("\n");
	printf("\\** End Typing: ****************************************/\n\n\n");
}

void printfTyping(FILE * f, struct TYPING * types){
	int i;

	fprintf(f,"\\** Typing: *********************************************/\n");
	fprintf(f,"Typed Object List:\n");
	for(i=0;i<types->nbobj;i++){
		fprintf(f,"------------------------\n");
		printfTypedObject(f,&types->objects[i],i);
	}
	fprintf(f,"------------------------\n");
	fprintf(f,"\n");
	fprintf(f,"\\** End Typing: ****************************************/\n\n\n");
}

void storeTypedObject(FILE * db, struct TYPED_OBJ * object){
	int idata; char cdata = 0;
	//Storing characteristics
	if(object->ObjectName[0]!=0){ //Name presence
		cdata = 'n';
		fwrite(&cdata,sizeof(char),1,db);
		fprintf(db,"%s",object->ObjectName);
		cdata = '\n';
		fwrite(&cdata,sizeof(char),1,db); //End of line terminated string
	}else{
		cdata = 'u';
		fwrite(&cdata,sizeof(char),1,db);
	}
	idata = object->Type;
	fwrite(&idata,sizeof(int),1,db);
	idata = object->Nature;
	fwrite(&idata,sizeof(int),1,db);
	idata = object->Status;
	fwrite(&idata,sizeof(int),1,db);
}


void storeTyping(FILE * db, struct TYPING * types){
	int i,nb = types->nbobj;
	fwrite(&nb,sizeof(int),1,db);
	for(i=0;i<nb;i++){
		storeTypedObject(db,&types->objects[i]);
	}
}

int isKnownObject(struct TYPING * types, char *  name,  unsigned long ref){
	int i, j, len;
	char unquoted[TOKENSIZE];
	
	if(name!=NULL){
		//Unquoting name if required
		if(name[0]=='"'){
			len = (int)strlen(name);
			if(len>2&&len<TOKENSIZE){
				strcpy(unquoted,&name[1]);
				unquoted[len-2] = '\0';
				strcpy(name,unquoted);
			}
		}
		

		//Look for the desired name
		for(i=0;i<types->nbobj;i++){
			if(!strncasecmp(name,types->objects[i].ObjectName,TOKENSIZE)){ return i;}
			//if(q){if(!strncasecmp(unquoted,types->objects[i].ObjectName,TOKENSIZE)) return i;}
		}
		return -1;
	}else{
		for(i=0;i<types->nbobj;i++){
			//Checks addresses
			if(ref==types->objects[i].Address) return i;
			len = getObjectSize(types,i);
			if(len){
				if((ref>types->objects[i].Address)
					&& (ref<(types->objects[i].Address+len))) return i;
			}
			//Checks handles
			for(j=0;j<types->objects[i].nbref;j++){
				if(ref==types->objects[i].Handles[j]) return i;
			}
		}
		return -1;
	}
}


int addNewObject(struct TYPING * types, char *  name, int nature){
	int index = types->nbobj;
	types->nbobj++;
	//Name
	if(name)
		strcpy(types->objects[index].ObjectName,name);
	types->objects[index].Nature = nature;
	types->objects[index].Status = 0;
	updateObjectType(types,index);
	return index;
}

unsigned long getObjectAddress(struct TYPING * types, int obj){
	return types->objects[obj].Address;
}

int getObjectType(struct TYPING * types, int obj){
	return types->objects[obj].Type;
}

int getObjectNature(struct TYPING * types, int obj){
	return types->objects[obj].Nature;
}

int getObjectSize(struct TYPING * types, int obj){
	return types->objects[obj].Size;
}

void setObjectType(struct TYPING * types, int obj, int type){
	types->objects[obj].Type = type;
}

void setObjectNature(struct TYPING * types, int obj, int nature){
		types->objects[obj].Nature = nature;
}

void setObjectStatus(struct TYPING * types, int obj, int status){
		types->objects[obj].Status = status;
}

void setObjectAddress(struct TYPING * types, int obj, unsigned long address){
	types->objects[obj].Address = address;
}

void setObjectSize(struct TYPING * types, int obj, int size){
		types->objects[obj].Size = size;
}

void addObjectHandle(struct TYPING * types, int obj, unsigned long handle){
	int objk,i;
	int nb = types->objects[obj].nbref;
	//Checks for existing reference
	objk = isKnownObject(types,NULL,handle);
	if(objk>-1){
		if(objk==obj) return;
		removeObjectHandle(types,objk,handle);
	}
	//If the maximum handle number is reached, cyclical permutation
	if(nb==MAXNBREF){
		for(i=MAXNBREF-1;i>1;i--){
			types->objects[obj].Handles[i-1] = types->objects[obj].Handles[i];
		}
		types->objects[obj].Handles[0] = handle;
	}else{
		types->objects[obj].nbref++;
		types->objects[obj].Handles[nb] = handle;
	}
}

void removeObjectHandle(struct TYPING * types, int obj, unsigned long handle){
	int i, j, nb = types->objects[obj].nbref;
	//Looks for the handle index
	for(i=0; i<nb; i++){
		if(handle==types->objects[obj].Handles[i]){
			for(j=i; j<nb-1; j++){
				types->objects[obj].Handles[j] =
					types->objects[obj].Handles[j+1];
			}
			types->objects[obj].nbref--;
			break;
		}//reference found
	}
}

void updateObjectType(struct TYPING * types, int obj){
	int highesttype = types->objects[obj].Type;
	int nature = types->objects[obj].Nature;
	int highestnature = nature;
	int type;
	
	if(nature==VAR){
		types->objects[obj].Type = TYPE_VAR;
		return;
	}

	//Classification by name
	if(types->objects[obj].ObjectName[0]!=0){
		ClassifyObject(types->objects[obj].ObjectName,0,&type,&nature);
		if(type > highesttype){
			highesttype = type;
			highestnature = nature;
		}
	}
	//Classification by address 
	//TODO
	setObjectType(types,obj,highesttype);
	setObjectNature(types,obj,highestnature);
}

